<?php
#### SESSION ###################################################################
class Session {

	var $username;
	var $password;
	var $remember;

	#### CONSTRUCTOR ###########################################################
	function Session() {
		Base::getThis();

		// Invoke custom session handler
		if ($this->config['session']['use_database']) {
			session_set_save_handler(
				array($this, 'open'),
				array($this, 'close'),
				array($this, 'read'),
				array($this, 'write'),
				array($this, 'destroy'),
				array($this, 'clean')
				);
		}

		session_start();

		// Update session reference
		$this->sessvar =& $_SESSION['lf'];
	}

	#### LOGIN #################################################################
	function login() {

		$this->db->select($this->db->table['users']);
		$this->db->where("username='".$this->username."'");
		$this->db->query() or sql_error(__FILE__, __LINE__);
		$this->user = $this->db->fetchArray();

		// If user exists
		if ($this->user['user_id'] > 0) {

			$this->load->helper('password');
			$password_hash = password_hash($this->password);

			// If there is no registration date, generate new random one
			// This is only used to set the registration date of the admin upon installation
			if ($this->user['register_datetime'] == '0000-00-00 00:00:00') {
				$sql = "UPDATE ".$this->db->table['users']." SET register_datetime = '".datetime()."' WHERE user_id = ".$this->user['user_id']."";
				$this->db->query($sql, $this->db->connection['users']) or sql_error(__FILE__, __LINE__);
			}

			// If there is no cookie_id, generate new random one
			if (!$this->user['cookie_id']) {
				$cookie_id = mt_rand(1, mt_getrandmax());
				$cookie_id = md5(uniqid($cookie_id));
				$sql = "UPDATE ".$this->db->table['users']." SET cookie_id = '".$cookie_id."' WHERE user_id = ".$this->user['user_id']."";
				$this->db->query($sql, $this->db->connection['users']) or sql_error(__FILE__, __LINE__);
			}

			// If password is correct create login session
			if ($this->user['password'] == $password_hash) {
				// Create the session
				$this->create($this->remember);
				return TRUE;
			}
		}

		return FALSE;
	}

	#### LOGOUT ################################################################
	function logout($message = FALSE) {
		// Destroy session
		unset($_SESSION['lf']);

		// Destroy cookie
		variable($cookie, $this->config['cookie']['name'], 'cookie', NULL);
		if ($cookie) setcookie($this->config['cookie']['name'], $cookie, time() - 3600, $this->config['cookie']['path'], $this->config['cookie']['domain'], $this->config['cookie']['secure']);

		if ($message) die($message);
	}

	#### CHECK SESSION #########################################################
	function check($check_cookie = FALSE) {

		// If a valid cookie exists a new valid session will be created
		if ($check_cookie == TRUE && !isset($this->sessvar['login']['user_id'])) $this->checkCookie();

		// Check the current session, is it valid or not?
		if (isset($this->sessvar['login']['user_id'])) {
			$this->db->sql = "SELECT user_id, session_ip, session_id FROM ".$this->db->table['users']." WHERE user_id = ".$this->sessvar['login']['user_id']."";
			$rows = $this->db->cache('users/'.$this->sessvar['login']['username']);

			// If no row is returned the login is incorrect and session check is void
			if (!$rows) return FALSE;

			foreach ($rows as $row) {
				// If enabled, it only checks if the session exists
				if ($this->config['session']['check_session_simple'] == FALSE && $this->sessvar['login']['user_id']) return TRUE;

				// If session ID in database does not match current session ID
				if ($row['session_id'] != session_id()) $this->logout('Invalid Session ID');

				// If session IP in database does not match current session IP
				if ($this->config['session']['check_session_ip'] && $row['session_ip'] != $_SERVER['REMOTE_ADDR']) $this->logout('Invalid Session IP');

				// If we made it this far...
				return TRUE;
			}
		}
		else {
			// Populate user sessvar with NULL value
			$this->sessvar['login'] = NULL;
		}
	}

	#### CHECK COOKIE ##########################################################
	function checkCookie() {

		variable($cookie, $this->config['cookie']['name'], 'cookie', NULL);

		// If there isn't a cookie to check we should just return
		if(!$cookie) return;

		$cookie = explode('|', base64_decode($cookie));
		$cookie_username = $cookie[0];
		$cookie_user_id = $cookie[1];
		$cookie_cookie_id = $cookie[2];

		// If part of the cookie is missing, destroy it
		if ($cookie_username == NULL || $cookie_user_id == NULL || $cookie_cookie_id == NULL) {
			setcookie($this->config['cookie']['name'], '', time() - 3600, $this->config['cookie']['path'], $this->config['cookie']['domain'], $this->config['cookie']['secure']);
			return FALSE;
		}
		else {
			$sql = "SELECT * FROM ".$this->db->table['users']." WHERE user_id = ".$cookie_user_id." AND cookie_id = '".$cookie_cookie_id."'";
			$result = $this->db->query($sql, $this->db->connection['users']) or sql_error(__FILE__, __LINE__);
			$this->user = $this->db->fetchArray($result);

			// If user_id exists, create session and update cookie
			if ($this->user['user_id']) {
				$this->create();
				return TRUE;
			}
			else return FALSE;
		}
	}

	#### CREATE SESSION ########################################################
	function create($create_cookie = FALSE) {
		// Setup session vars
		$this->sessvar['login'] = $this->user;
		$this->sessvar['login']['last_login_ip'] = $this->user['session_ip'];
		$this->sessvar['login']['session_ip'] = $_SERVER['REMOTE_ADDR'];
		if (function_exists('get_roles_array')) $this->sessvar['login']['roles'] = get_roles_array();

		// Update user in database
		$sql_array['session_id'] = session_id();
		$sql_array['session_ip'] = $_SERVER['REMOTE_ADDR'];
		$sql_array['last_login_datetime'] = datetime();
		$this->db->update($this->db->table['users'], $sql_array);
		$this->db->where('user_id='.$this->user['user_id']);

		// Perform the query
		$this->db->query() or sql_error(__FILE__, __LINE__);

		if ($create_cookie) $this->createCookie();
	}

	#### CREATE COOKIE #########################################################
	function createCookie() {
		// Seconds Minutes Hours Days
		$cookie_expire_time = 60*60*24*30;

		$cookie = base64_encode($this->user['username'].'|'.$this->user['user_id'].'|'.$this->user['cookie_id']);
		setcookie($this->config['cookie']['name'], $cookie, time() + $cookie_expire_time, $this->config['cookie']['path'], $this->config['cookie']['domain'], $this->config['cookie']['secure']);
	}


	#### CUSTOM SESSION HANDLING METHODS #######################################


	#### OPEN ##################################################################
	function open() {
		// Nothing to see here
	}

	#### CLOSE #################################################################
	function close() {
		// Or here
	}

	#### READ ##################################################################
	function read($id) {
		$sql = "SELECT data FROM ".$this->db->table['sessions']." WHERE
			id = '".$id."'";
		$this->db->query($sql, $this->db->connection['sessions']) or sql_error(__FILE__, __LINE__);
		$row = $this->db->fetchArray();

		// Must return an empty string if no session data exists
		if (isset($row['data'])) return $row['data'];
		else return '';
	}

	#### WRITE #################################################################
	function write($id, $data) {
		$sql = "REPLACE INTO ".$this->db->table['sessions']." SET
			id = '".$id."',
			lastaccess = '".time()."',
			data = '".$data."'";
		$this->db->query($sql, $this->db->connection['sessions']) or sql_error(__FILE__, __LINE__);

        if($this->db->affectedRows()) return true;
        else return false;
	}

	#### DESTROY ###############################################################
	function destroy($id) {
		$sql = "DELETE FROM ".$this->db->table['sessions']." WHERE
			id = '".$id."'";
		$this->db->query($sql, $this->db->connection['sessions']) or sql_error(__FILE__, __LINE__);

        if($this->db->affectedRows()) return true;
        else return false;
	}

	#### CLEAN #################################################################
	function clean() {
		$timeout = time() - get_cfg_var('session.gc_maxlifetime');
		$sql = "DELETE FROM ".$this->db->table['sessions']." WHERE
			lastaccess < '".$timeout."'";
		$this->db->query($sql, $this->db->connection['sessions']) or sql_error(__FILE__, __LINE__);

		return $this->db->affectedRows();
	}
}
?>